// Copyright DustedPixels.com 2008. All rights reserved.

package com.dustedpixels.asm.test;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.MethodAdapter;

import com.dustedpixels.asm.AsmClassLoader;
import com.dustedpixels.asm.tree.TreeUtils;
import com.dustedpixels.asm.utils.MethodInliner;


/**
 * @author micapolos@gmail.com (Michal Pociecha-Los)
 */
public final class MethodInlinerBenchmark {
  private static final int TIMES = 100000000;

  public int repeat(int times) {
    int a = 1;
    int b = 2;
    for (int i = 0; i < times; i++) {
      a = add(a, b);
      b = add(b, a);
    }
    return a;
  }
  
  private int add(int a, int b) {
    return a + b;
  }
  
  public static void main(String[] args) throws Exception {
    long time;
    
    MethodInlinerBenchmark benchmark = new MethodInlinerBenchmark();
    time = System.currentTimeMillis();
    int result = benchmark.repeat(TIMES);
    System.out.println("Benchmark (" + result + "): " + (System.currentTimeMillis() - time) + "ms");

    final ClassNode clazz = TreeUtils.load("asm.test.MethodInlinerBenchmark");
    final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    final MethodNode inlinedMethod = TreeUtils.getMethod(clazz, "repeat", "(I)I");
    clazz.accept(new ClassAdapter(classWriter) {
      @Override
      public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions);
        if (name.equals("repeat")) {
          visitor = new MethodInliner(visitor, clazz.name, "(I)I", inlinedMethod);
        }
        return visitor;
      }
    });
    Class cl = AsmClassLoader.loadClass("asm.test.MethodInlinerBenchmark", classWriter.toByteArray());
    cl.newInstance();
    time = System.currentTimeMillis();
    int result = benchmark.repeat(TIMES);
    System.out.println("Benchmark (" + result + "): " + (System.currentTimeMillis() - time) + "ms");
  }
}
